package com.tarena.lbs.article.web.repository;

import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.pojo.content.entity.ArticleSearchEntity;
import com.tarena.lbs.pojo.content.query.ArticleQuery;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RestController
@Slf4j
public class ArticleRepository {
    @Autowired
    private RestHighLevelClient client;
    @Autowired
    private ArticleESRepository articleESRepository;
    public PageResult<ArticleSearchEntity> getEntityPages(ArticleQuery query) {
        //1.创建请求对象 查询请求 SearchRequest
        SearchRequest searchRequest=new SearchRequest("lbs_article");
        //2.请求一定携带了请求参数 SearchSourceBuilder
        SearchSourceBuilder builder=new SearchSourceBuilder();
        //2.1 分页 去重 排序(默认排序评分)
        int from=(query.getPageNo()-1)* query.getPageSize();
        builder.from(from).size(query.getPageSize());
        //2.2 构造具体查询条件 由于条件多样化 可能只查询标题 可能同时查询标题和作者和状态
        //了解了mapping映射 构造符合查询 bool articleTile 文本搜索MatchQuery articleStatus TermQuery
        //userId TermQuery source TermQuery(只查询source=2) start end rangeQuery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //字条件判断非空
        if (StringUtils.isNotBlank(query.getArticleTitle())){
            boolQuery.must(QueryBuilders.matchQuery("articleTitle",query.getArticleTitle()));
        }
        if(CollectionUtils.isNotEmpty(query.getArticleStatus())){
            //取第一个只 0下线 1上线
            Integer status = query.getArticleStatus().get(0);
            boolQuery.must(QueryBuilders.termQuery("articleStatus",status));
        }
        if(query.getUserId()!=null){
            boolQuery.must(QueryBuilders.termQuery("userId",query.getUserId()));
        }
        if (query.getSource()!=null){
            boolQuery.must(QueryBuilders.termQuery("source",query.getSource()));
        }
        if (query.getUpdateStartTime()!=null&&query.getUpdateEndTime()!=null){
            boolQuery.must(QueryBuilders.rangeQuery("updateTime").gte(query.getUpdateStartTime()).lte(query.getUpdateEndTime()));
        }
        //添加前台查询属性 非空判断 label location
        if (query.getLatitude()!=null&&query.getLongitude()!=null){
            GeoDistanceQueryBuilder geoQuery = QueryBuilders.geoDistanceQuery("location");
            GeoPoint geoPoint=new GeoPoint(Double.parseDouble(query.getLatitude()),Double.parseDouble(query.getLongitude()));
            geoQuery.distance(50d, DistanceUnit.KILOMETERS).point(geoPoint);
            boolQuery.must(geoQuery);
        }
        if (StringUtils.isNotBlank(query.getArticleLabel())){
            boolQuery.must(QueryBuilders.termQuery("articleLabel",query.getArticleLabel()));
        }
        builder.query(boolQuery);
        log.info("查询条件:{}",builder);
        //2.3 source交给请求对象
        searchRequest.source(builder);
        //3.发起请求
        SearchResponse searchResponse=null;
        try{
            searchResponse= client.search(searchRequest, RequestOptions.DEFAULT);
        }catch (Exception e){
            //打印错误日志
            log.error("查询 文章出现问题",e);
        }
        //4 解析响应 返回结果
        PageResult<ArticleSearchEntity> entityPages=new PageResult<>();
        entityPages.setPageSize(query.getPageSize());
        entityPages.setPageNo(query.getPageNo());
        if (searchResponse!=null){
            //查到结果 才能封装另外2个属性total objects
            long total = searchResponse.getHits().getTotalHits().value;
            entityPages.setTotal(total);
            List<ArticleSearchEntity> entities=null;
            if (total>0){
               entities=new ArrayList<>();
               SearchHit[] hits = searchResponse.getHits().getHits();
               for (SearchHit hit : hits) {
                    String articleJson=hit.getSourceAsString();
                    entities.add(JSON.parseObject(articleJson,ArticleSearchEntity.class));
               }
            }
            entityPages.setObjects(entities);
        }
        return entityPages;
        /*ArticleSearchEntity similarEntity=new ArticleSearchEntity();
        similarEntity.setUserId(query.getUserId());
        similarEntity.setArticleStatus(query.getArticleStatus().get(0));
        PageRequest pageRequest = PageRequest.of(0, 10);
        articleESRepository.searchSimilar(similarEntity,null,pageRequest);*/
    }

    public List<ArticleSearchEntity> getArticleLabelsOnLocation(ArticleQuery articleQuery) throws IOException {
        //1.查询 构造一个请求request
        SearchRequest searchRequest=new SearchRequest("lbs_article");
        //2.设置请求参数 查询条件为主 根据标签值keyword 去重
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        //2.1 封装查询条件
        GeoDistanceQueryBuilder query = QueryBuilders.geoDistanceQuery("location");
        GeoPoint geoPoint=new GeoPoint(Double.parseDouble(articleQuery.getLatitude()),Double.parseDouble(articleQuery.getLongitude()));
        query.distance(50d, DistanceUnit.KILOMETERS).point(geoPoint);
        sourceBuilder.query(query);
        //2.2 根据标签属性 做查询结果的去重
        sourceBuilder.collapse(new CollapseBuilder("articleLabel"));
        searchRequest.source(sourceBuilder);
        //3.执行请求 解析结果 不需要解析分页数据 只需要解析list集合拿到文章entity
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //只要拿到查询数组
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<ArticleSearchEntity> entities=new ArrayList<>();
        if(searchResponse.getHits().getTotalHits().value>0){
            for (SearchHit hit : hits) {
                entities.add(JSON.parseObject(hit.getSourceAsString(),ArticleSearchEntity.class));
            }
        }
        return entities;
    }
}
